From 0b788798d8b3a652f32c99e7d89aa9eecfc3cbef Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Thu, 30 Dec 2004 14:20:11 +0000 Subject: [PATCH] bitkeeper revision 1.1159.207.3 (41d40e9b3_4vSbRgi7pJ9tnNxCToeQ) New generic I/O ring macros from Andrew Warfield and Tim Deegan. Currently only used for block-device channels. --- .rootkeys | 1 + .../drivers/xen/blkback/blkback.c | 64 ++--- .../drivers/xen/blkback/common.h | 23 +- .../drivers/xen/blkback/interface.c | 23 +- .../drivers/xen/blkfront/blkfront.c | 135 +++++----- .../drivers/xen/blkfront/block.h | 1 + xen/include/public/io/blkif.h | 24 +- xen/include/public/io/ring.h | 254 ++++++++++++++++++ 8 files changed, 388 insertions(+), 137 deletions(-) create mode 100644 xen/include/public/io/ring.h diff --git a/.rootkeys b/.rootkeys index 8c10a9751c..bc4f73b249 100644 --- a/.rootkeys +++ b/.rootkeys @@ -860,6 +860,7 @@ 40dc4076pVeE1kEEWzcUaNZin65kCA xen/include/public/io/domain_controller.h 41c0c412FLc0gunlJl91qMYscFtXVA xen/include/public/io/ioreq.h 40f5623cTZ80EwjWUBlh44A9F9i_Lg xen/include/public/io/netif.h +41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h 4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h 40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h 404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c b/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c index b3d195cb0d..6167f6061b 100644 --- a/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c +++ b/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c @@ -74,12 +74,11 @@ static kmem_cache_t *buffer_head_cachep; * If the tap driver is used, we may get pages belonging to either the tap * or (more likely) the real frontend. The backend must specify which domain * a given page belongs to in update_va_mapping though. For the moment, - * we pass in the domid of the real frontend in PROBE messages and store - * this value in alt_dom. Then on mapping, we try both. This is a Guiness - * book of records-calibre grim hack, and represents a bit of a security risk. - * Grant tables will soon solve the problem though! + * the tap rewrites the ID field of the request to contain the request index + * and the id of the real front end domain. */ -static domid_t alt_dom = 0; +#define BLKTAP_COOKIE 0xbeadfeed +static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); } #endif static int do_block_io_op(blkif_t *blkif, int max_to_do); @@ -279,17 +278,16 @@ irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs) static int do_block_io_op(blkif_t *blkif, int max_to_do) { - blkif_ring_t *blk_ring = blkif->blk_ring_base; + blkif_back_ring_t *blk_ring = &blkif->blk_ring; blkif_request_t *req; - BLKIF_RING_IDX i, rp; + RING_IDX i, rp; int more_to_do = 0; - rp = blk_ring->req_prod; + rp = blk_ring->sring->req_prod; rmb(); /* Ensure we see queued requests up to 'rp'. */ - /* Take items off the comms ring, taking care not to overflow. */ - for ( i = blkif->blk_req_cons; - (i != rp) && ((i-blkif->blk_resp_prod) != BLKIF_RING_SIZE); + for ( i = blk_ring->req_cons; + (i != rp) && !RING_REQUEST_CONS_OVERFLOW(BLKIF_RING, blk_ring, i); i++ ) { if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) ) @@ -298,7 +296,7 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do) break; } - req = &blk_ring->ring[MASK_BLKIF_IDX(i)].req; + req = RING_GET_REQUEST(BLKIF_RING, blk_ring, i); switch ( req->operation ) { case BLKIF_OP_READ: @@ -312,14 +310,13 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do) default: DPRINTK("error: unknown block io operation [%d]\n", - blk_ring->ring[i].req.operation); - make_response(blkif, blk_ring->ring[i].req.id, - blk_ring->ring[i].req.operation, BLKIF_RSP_ERROR); + req->operation); + make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); break; } } - blkif->blk_req_cons = i; + blk_ring->req_cons = i; return more_to_do; } @@ -339,24 +336,26 @@ static void dispatch_probe(blkif_t *blkif, blkif_request_t *req) #ifdef CONFIG_XEN_BLKDEV_TAP_BE /* Grab the real frontend out of the probe message. */ - alt_dom = (domid_t)req->frame_and_sects[1]; + if (req->frame_and_sects[1] == BLKTAP_COOKIE) + blkif->is_blktap = 1; #endif - + + +#ifdef CONFIG_XEN_BLKDEV_TAP_BE if ( HYPERVISOR_update_va_mapping_otherdomain( MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT, (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL }, - 0, blkif->domid) ) { -#ifdef CONFIG_XEN_BLKDEV_TAP_BE - /* That didn't work. Try alt_dom. */ - if ( HYPERVISOR_update_va_mapping_otherdomain( - MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT, - (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL }, - 0, alt_dom) ) - goto out; -#else + 0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) ) + + goto out; +#else + if ( HYPERVISOR_update_va_mapping_otherdomain( + MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT, + (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL }, + 0, blkif->domid) ) + goto out; #endif - } rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0), PAGE_SIZE / sizeof(vdisk_t)); @@ -441,7 +440,7 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req) mcl[i].args[1] = (phys_seg[i].buffer & PAGE_MASK) | remap_prot; mcl[i].args[2] = 0; #ifdef CONFIG_XEN_BLKDEV_TAP_BE - mcl[i].args[3] = (alt_dom != 0) ? alt_dom : blkif->domid; + mcl[i].args[3] = (blkif->is_blktap) ? ID_TO_DOM(req->id) : blkif->domid; #else mcl[i].args[3] = blkif->domid; #endif @@ -558,16 +557,17 @@ static void make_response(blkif_t *blkif, unsigned long id, { blkif_response_t *resp; unsigned long flags; + blkif_back_ring_t *blk_ring = &blkif->blk_ring; /* Place on the response ring for the relevant domain. */ spin_lock_irqsave(&blkif->blk_ring_lock, flags); - resp = &blkif->blk_ring_base-> - ring[MASK_BLKIF_IDX(blkif->blk_resp_prod)].resp; + resp = RING_GET_RESPONSE(BLKIF_RING, blk_ring, blk_ring->rsp_prod_pvt); resp->id = id; resp->operation = op; resp->status = st; wmb(); /* Ensure other side can see the response fields. */ - blkif->blk_ring_base->resp_prod = ++blkif->blk_resp_prod; + blk_ring->rsp_prod_pvt++; + RING_PUSH_RESPONSES(BLKIF_RING, blk_ring); spin_unlock_irqrestore(&blkif->blk_ring_lock, flags); /* Kick the relevant domain. */ diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h b/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h index 4a12ca8fe9..1df08d43cd 100644 --- a/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h +++ b/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h @@ -15,6 +15,7 @@ #include #include #include +#include #if 0 #define ASSERT(_p) \ @@ -36,19 +37,17 @@ struct block_device; typedef struct blkif_st { /* Unique identifier for this interface. */ - domid_t domid; - unsigned int handle; + domid_t domid; + unsigned int handle; /* Physical parameters of the comms window. */ - unsigned long shmem_frame; - unsigned int evtchn; - int irq; + unsigned long shmem_frame; + unsigned int evtchn; + int irq; /* Comms information. */ - blkif_ring_t *blk_ring_base; /* ioremap()'ed ptr to shmem_frame. */ - BLKIF_RING_IDX blk_req_cons; /* Request consumer. */ - BLKIF_RING_IDX blk_resp_prod; /* Private version of resp. producer. */ + blkif_back_ring_t blk_ring; /* VBDs attached to this interface. */ - rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs. */ - spinlock_t vbd_lock; /* Protects VBD mapping. */ + rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs.*/ + spinlock_t vbd_lock; /* Protects VBD mapping. */ /* Private fields. */ enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; /* @@ -56,6 +55,10 @@ typedef struct blkif_st { * We therefore need to store the id from the original request. */ u8 disconnect_rspid; +#ifdef CONFIG_XEN_BLKDEV_TAP_BE + /* Is this a blktap frontend */ + unsigned int is_blktap; +#endif struct blkif_st *hash_next; struct list_head blkdev_list; spinlock_t blk_ring_lock; diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c b/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c index 4196014597..087e02d620 100644 --- a/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c +++ b/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c @@ -39,7 +39,7 @@ static void __blkif_disconnect_complete(void *arg) * must still be notified to the remote driver. */ unbind_evtchn_from_irq(blkif->evtchn); - vfree(blkif->blk_ring_base); + vfree(blkif->blk_ring.sring); /* Construct the deferred response message. */ cmsg.type = CMSG_BLKIF_BE; @@ -149,14 +149,15 @@ void blkif_destroy(blkif_be_destroy_t *destroy) void blkif_connect(blkif_be_connect_t *connect) { - domid_t domid = connect->domid; - unsigned int handle = connect->blkif_handle; - unsigned int evtchn = connect->evtchn; - unsigned long shmem_frame = connect->shmem_frame; + domid_t domid = connect->domid; + unsigned int handle = connect->blkif_handle; + unsigned int evtchn = connect->evtchn; + unsigned long shmem_frame = connect->shmem_frame; struct vm_struct *vma; - pgprot_t prot; - int error; - blkif_t *blkif; + pgprot_t prot; + int error; + blkif_t *blkif; + blkif_sring_t *sring; blkif = blkif_find_by_handle(domid, handle); if ( unlikely(blkif == NULL) ) @@ -195,11 +196,13 @@ void blkif_connect(blkif_be_connect_t *connect) vfree(vma->addr); return; } - + sring = (blkif_sring_t *)vma->addr; + SHARED_RING_INIT(BLKIF_RING, sring); + BACK_RING_INIT(BLKIF_RING, &blkif->blk_ring, sring); + blkif->evtchn = evtchn; blkif->irq = bind_evtchn_to_irq(evtchn); blkif->shmem_frame = shmem_frame; - blkif->blk_ring_base = (blkif_ring_t *)vma->addr; blkif->status = CONNECTED; blkif_get(blkif); diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c index 1d65f29b45..e3f345ac9b 100644 --- a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c +++ b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c @@ -6,6 +6,7 @@ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand * Modifications by Mark A. Williamson are (c) Intel Research Cambridge * Copyright (c) 2004, Christian Limpach + * Copyright (c) 2004, Andrew Warfield * * This file may be distributed separately from the Linux kernel, or * incorporated into other software packages, subject to the following license: @@ -84,20 +85,14 @@ static unsigned int blkif_irq = 0; static int blkif_control_rsp_valid; static blkif_response_t blkif_control_rsp; -static blkif_ring_t *blk_ring = NULL; -static BLKIF_RING_IDX resp_cons; /* Response consumer for comms ring. */ -static BLKIF_RING_IDX req_prod; /* Private request producer. */ +static blkif_front_ring_t blk_ring; unsigned long rec_ring_free; -blkif_request_t rec_ring[BLKIF_RING_SIZE]; +blkif_request_t rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)]; static int recovery = 0; /* "Recovery in progress" flag. Protected * by the blkif_io_lock */ -/* We plug the I/O ring if the driver is suspended or if the ring is full. */ -#define BLKIF_RING_FULL (((req_prod - resp_cons) == BLKIF_RING_SIZE) || \ - (blkif_state != BLKIF_STATE_CONNECTED)) - static void kick_pending_request_queues(void); int __init xlblk_init(void); @@ -108,7 +103,7 @@ static inline int GET_ID_FROM_FREELIST( void ) { unsigned long free = rec_ring_free; - if ( free > BLKIF_RING_SIZE ) + if ( free > RING_SIZE(BLKIF_RING, &blk_ring) ) BUG(); rec_ring_free = rec_ring[free].id; @@ -169,8 +164,7 @@ static inline void translate_req_to_mfn(blkif_request_t *xreq, static inline void flush_requests(void) { DISABLE_SCATTERGATHER(); - wmb(); /* Ensure that the frontend can see the requests. */ - blk_ring->req_prod = req_prod; + RING_PUSH_REQUESTS(BLKIF_RING, &blk_ring); notify_via_evtchn(blkif_evtchn); } @@ -343,7 +337,7 @@ static int blkif_queue_request(struct request *req) return 1; /* Fill out a communications ring structure. */ - ring_req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req; + ring_req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt); id = GET_ID_FROM_FREELIST(); rec_ring[id].id = (unsigned long) req; @@ -372,8 +366,8 @@ static int blkif_queue_request(struct request *req) } } - req_prod++; - + blk_ring.req_prod_pvt++; + /* Keep a private copy so we can reissue requests when recovering. */ translate_req_to_pfn( &rec_ring[id], ring_req); @@ -400,7 +394,7 @@ void do_blkif_request(request_queue_t *rq) continue; } - if ( BLKIF_RING_FULL ) + if ( RING_FULL(BLKIF_RING, &blk_ring) ) { blk_stop_queue(rq); break; @@ -426,9 +420,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) { struct request *req; blkif_response_t *bret; - BLKIF_RING_IDX i, rp; + RING_IDX i, rp; unsigned long flags; - + spin_lock_irqsave(&blkif_io_lock, flags); if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) || @@ -437,18 +431,17 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) spin_unlock_irqrestore(&blkif_io_lock, flags); return IRQ_HANDLED; } - - rp = blk_ring->resp_prod; + + rp = blk_ring.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ - for ( i = resp_cons; i != rp; i++ ) + for ( i = blk_ring.rsp_cons; i != rp; i++ ) { unsigned long id; - bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp; + bret = RING_GET_RESPONSE(BLKIF_RING, &blk_ring, i); id = bret->id; req = (struct request *)rec_ring[id].id; - blkif_completion( &rec_ring[id] ); ADD_ID_TO_FREELIST(id); /* overwrites req */ @@ -477,9 +470,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) BUG(); } } - - resp_cons = i; + blk_ring.rsp_cons = i; + kick_pending_request_queues(); spin_unlock_irqrestore(&blkif_io_lock, flags); @@ -533,10 +526,11 @@ static void kick_pending_request_queues(void) { /* We kick pending request queues if the ring is reasonably empty. */ if ( (nr_pending != 0) && - ((req_prod - resp_cons) < (BLKIF_RING_SIZE >> 1)) ) + (RING_PENDING_REQUESTS(BLKIF_RING, &blk_ring) < + (RING_SIZE(&blk_ring) >> 1)) ) { /* Attempt to drain the queue, but bail if the ring becomes full. */ - while ( (nr_pending != 0) && !BLKIF_RING_FULL ) + while ( (nr_pending != 0) && !RING_FULL(BLKIF_RING, &blk_ring) ) do_blkif_request(pending_queues[--nr_pending]); } } @@ -830,8 +824,8 @@ static int blkif_queue_request(unsigned long id, (sg_dev == device) && (sg_next_sect == sector_number) ) { - - req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod-1)].req; + req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, + blk_ring.rsp_prod_pvt - 1); bh = (struct buffer_head *)id; bh->b_reqnext = (struct buffer_head *)rec_ring[req->id].id; @@ -851,7 +845,7 @@ static int blkif_queue_request(unsigned long id, return 0; } - else if ( BLKIF_RING_FULL ) + else if ( RING_FULL(BLKIF_RING, &blk_ring) ) { return 1; } @@ -868,7 +862,7 @@ static int blkif_queue_request(unsigned long id, } /* Fill out a communications ring structure. */ - req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req; + req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt); xid = GET_ID_FROM_FREELIST(); rec_ring[xid].id = id; @@ -880,11 +874,11 @@ static int blkif_queue_request(unsigned long id, req->nr_segments = 1; req->frame_and_sects[0] = buffer_ma | (fsect<<3) | lsect; - req_prod++; - /* Keep a private copy so we can reissue requests when recovering. */ translate_req_to_pfn(&rec_ring[xid], req ); + blk_ring.req_prod_pvt++; + return 0; } @@ -973,7 +967,7 @@ void do_blkif_request(request_queue_t *rq) static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) { - BLKIF_RING_IDX i, rp; + RING_IDX i, rp; unsigned long flags; struct buffer_head *bh, *next_bh; @@ -985,14 +979,15 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) return; } - rp = blk_ring->resp_prod; + rp = blk_ring.rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ - for ( i = resp_cons; i != rp; i++ ) + for ( i = blk_ring.rsp_cons; i != rp; i++ ) { unsigned long id; - blkif_response_t *bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp; - + blkif_response_t *bret; + + bret = RING_GET_RESPONSE(BLKIF_RING, &blkif_ring, i); id = bret->id; bh = (struct buffer_head *)rec_ring[id].id; @@ -1022,10 +1017,9 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) default: BUG(); } - } - - resp_cons = i; + blk_ring.rsp_cons = i; + kick_pending_request_queues(); spin_unlock_irqrestore(&io_request_lock, flags); @@ -1039,31 +1033,33 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp) { unsigned long flags, id; + blkif_request_t *req_d; retry: - while ( (req_prod - resp_cons) == BLKIF_RING_SIZE ) + while ( RING_FULL(BLKIF_RING, &blk_ring) ) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } spin_lock_irqsave(&blkif_io_lock, flags); - if ( (req_prod - resp_cons) == BLKIF_RING_SIZE ) + if ( RING_FULL(BLKIF_RING, &blk_ring) ) { spin_unlock_irqrestore(&blkif_io_lock, flags); goto retry; } DISABLE_SCATTERGATHER(); - blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req = *req; + req_d = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt); + *req_d = *req; id = GET_ID_FROM_FREELIST(); - blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req.id = id; + req_d->id = id; rec_ring[id].id = (unsigned long) req; translate_req_to_pfn( &rec_ring[id], req ); - req_prod++; + blk_ring.req_prod_pvt++; flush_requests(); spin_unlock_irqrestore(&blkif_io_lock, flags); @@ -1105,7 +1101,7 @@ static void blkif_send_interface_connect(void) blkif_fe_interface_connect_t *msg = (void*)cmsg.msg; msg->handle = 0; - msg->shmem_frame = (virt_to_machine(blk_ring) >> PAGE_SHIFT); + msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT); ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); } @@ -1119,10 +1115,10 @@ static void blkif_free(void) spin_unlock_irq(&blkif_io_lock); /* Free resources associated with old device channel. */ - if ( blk_ring != NULL ) + if ( blk_ring.sring != NULL ) { - free_page((unsigned long)blk_ring); - blk_ring = NULL; + free_page((unsigned long)blk_ring.sring); + blk_ring.sring = NULL; } free_irq(blkif_irq, NULL); blkif_irq = 0; @@ -1138,10 +1134,14 @@ static void blkif_close(void) /* Move from CLOSED to DISCONNECTED state. */ static void blkif_disconnect(void) { - if ( blk_ring != NULL ) - free_page((unsigned long)blk_ring); - blk_ring = (blkif_ring_t *)__get_free_page(GFP_KERNEL); - blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0; + blkif_sring_t *sring; + + if ( blk_ring.sring != NULL ) + free_page((unsigned long)blk_ring.sring); + + sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL); + SHARED_RING_INIT(BLKIF_RING, sring); + FRONT_RING_INIT(BLKIF_RING, &blk_ring, sring); blkif_state = BLKIF_STATE_DISCONNECTED; blkif_send_interface_connect(); } @@ -1155,34 +1155,37 @@ static void blkif_reset(void) static void blkif_recover(void) { int i; + blkif_request_t *req; /* Hmm, requests might be re-ordered when we re-issue them. * This will need to be fixed once we have barriers */ /* Stage 1 : Find active and move to safety. */ - for ( i = 0; i < BLKIF_RING_SIZE; i++ ) + for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ ) { if ( rec_ring[i].id >= PAGE_OFFSET ) { - translate_req_to_mfn( - &blk_ring->ring[req_prod].req, &rec_ring[i]); - req_prod++; + req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, + blk_ring.req_prod_pvt); + translate_req_to_mfn(req, &rec_ring[i]); + blk_ring.req_prod_pvt++; } } /* Stage 2 : Set up shadow list. */ - for ( i = 0; i < req_prod; i++ ) + for ( i = 0; i < blk_ring.req_prod_pvt; i++ ) { - rec_ring[i].id = blk_ring->ring[i].req.id; - blk_ring->ring[i].req.id = i; - translate_req_to_pfn(&rec_ring[i], &blk_ring->ring[i].req); + req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, i); + rec_ring[i].id = req->id; + req->id = i; + translate_req_to_pfn(&rec_ring[i], req); } /* Stage 3 : Set up free list. */ - for ( ; i < BLKIF_RING_SIZE; i++ ) + for ( ; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ ) rec_ring[i].id = i+1; - rec_ring_free = req_prod; - rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff; + rec_ring_free = blk_ring.req_prod_pvt; + rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff; /* blk_ring->req_prod will be set when we flush_requests().*/ wmb(); @@ -1376,9 +1379,9 @@ int __init xlblk_init(void) printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n"); rec_ring_free = 0; - for ( i = 0; i < BLKIF_RING_SIZE; i++ ) + for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ ) rec_ring[i].id = i+1; - rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff; + rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff; (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx, CALLBACK_IN_BLOCKING_CONTEXT); diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h index f50ce03bca..487a83967e 100644 --- a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h +++ b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/include/public/io/blkif.h b/xen/include/public/io/blkif.h index 8cd3696eb6..4108f4e545 100644 --- a/xen/include/public/io/blkif.h +++ b/xen/include/public/io/blkif.h @@ -9,6 +9,8 @@ #ifndef __XEN_PUBLIC_IO_BLKIF_H__ #define __XEN_PUBLIC_IO_BLKIF_H__ +#include + #define blkif_vdev_t u16 #define blkif_sector_t u64 @@ -52,27 +54,11 @@ typedef struct { #define BLKIF_RSP_OKAY 0 /* non-specific 'okay' */ /* - * We use a special capitalised type name because it is _essential_ that all - * arithmetic on indexes is done on an integer type of the correct size. - */ -typedef u32 BLKIF_RING_IDX; - -/* - * Ring indexes are 'free running'. That is, they are not stored modulo the - * size of the ring buffer. The following macro converts a free-running counter - * into a value that can directly index a ring-buffer array. + * Generate blkif ring structures and types. */ -#define MASK_BLKIF_IDX(_i) ((_i)&(BLKIF_RING_SIZE-1)) - -typedef struct { - BLKIF_RING_IDX req_prod; /* 0: Request producer. Updated by front-end. */ - BLKIF_RING_IDX resp_prod; /* 4: Response producer. Updated by back-end. */ - union { /* 8 */ - blkif_request_t req; - blkif_response_t resp; - } PACKED ring[BLKIF_RING_SIZE]; -} PACKED blkif_ring_t; +#define BLKIF_RING RING_PARAMS(blkif_request_t, blkif_response_t, PAGE_SIZE) +DEFINE_RING_TYPES(blkif, BLKIF_RING); /* * BLKIF_OP_PROBE: diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h new file mode 100644 index 0000000000..8efeac4e98 --- /dev/null +++ b/xen/include/public/io/ring.h @@ -0,0 +1,254 @@ +/* + * Shared producer-consumer ring macros. + * Tim Deegan and Andrew Warfield November 2004. + */ + +#ifndef __XEN_PUBLIC_IO_RING_H__ +#define __XEN_PUBLIC_IO_RING_H__ + +typedef unsigned int RING_IDX; + +/* This is horrible: it rounds a 32-bit unsigned constant down to the + * nearest power of two, by finding the highest set bit. */ +#define __RD2PO2(_x) (((_x) & 0x80000000) ? 0x80000000 : \ + ((_x) & 0x40000000) ? 0x40000000 : \ + ((_x) & 0x20000000) ? 0x20000000 : \ + ((_x) & 0x10000000) ? 0x10000000 : \ + ((_x) & 0x08000000) ? 0x08000000 : \ + ((_x) & 0x04000000) ? 0x04000000 : \ + ((_x) & 0x02000000) ? 0x02000000 : \ + ((_x) & 0x01000000) ? 0x01000000 : \ + ((_x) & 0x00800000) ? 0x00800000 : \ + ((_x) & 0x00400000) ? 0x00400000 : \ + ((_x) & 0x00200000) ? 0x00200000 : \ + ((_x) & 0x00100000) ? 0x00100000 : \ + ((_x) & 0x00080000) ? 0x00080000 : \ + ((_x) & 0x00040000) ? 0x00040000 : \ + ((_x) & 0x00020000) ? 0x00020000 : \ + ((_x) & 0x00010000) ? 0x00010000 : \ + ((_x) & 0x00008000) ? 0x00008000 : \ + ((_x) & 0x00004000) ? 0x00004000 : \ + ((_x) & 0x00002000) ? 0x00002000 : \ + ((_x) & 0x00001000) ? 0x00001000 : \ + ((_x) & 0x00000800) ? 0x00000800 : \ + ((_x) & 0x00000400) ? 0x00000400 : \ + ((_x) & 0x00000200) ? 0x00000200 : \ + ((_x) & 0x00000100) ? 0x00000100 : \ + ((_x) & 0x00000080) ? 0x00000080 : \ + ((_x) & 0x00000040) ? 0x00000040 : \ + ((_x) & 0x00000020) ? 0x00000020 : \ + ((_x) & 0x00000010) ? 0x00000010 : \ + ((_x) & 0x00000008) ? 0x00000008 : \ + ((_x) & 0x00000004) ? 0x00000004 : \ + ((_x) & 0x00000002) ? 0x00000002 : \ + ((_x) & 0x00000001) ? 0x00000001 : 0x00000000) + +/* Given a shared ring, tell me how many entries there are in it. The + * rule is: a ring contains as many entries as will fit, rounded down to + * the nearest power of two (so we can mask with (size-1) to loop + * around) */ +#define __SRING_SIZE(__params, __esize) \ + __RD2PO2((sizeof((__params)->size) - (2 * sizeof(RING_IDX))) / (__esize)) +#define SRING_SIZE(__params, __sringp) \ + __SRING_SIZE(__params, sizeof (__sringp)->ring[0]) + +/* + * Macros to make the correct C datatypes for a new kind of ring. + * + * To make a new ring datatype, you need to have two message structures, + * let's say request_t, and response_t already defined. You also need to + * know how big the shared memory region you want the ring to occupy is + * (PAGE_SIZE, of instance). + * + * In a header where you want the ring datatype declared, you then do: + * + * #define MY_RING RING_PARAMS(request_t, response_t, PAGE_SIZE) + * DEFINE_RING_TYPES(mytag, MY_RING); + * + * These expand out to give you a set of types, as you can see below. + * The most important of these are: + * + * mytag_sring_t - The shared ring. + * mytag_front_ring_t - The 'front' half of the ring. + * mytag_back_ring_t - The 'back' half of the ring. + * + * Use the RING_PARAMS define (MY_RING above) as a first parameter on all + * the ring functions. To initialize a ring in your code, on the front + * half, you do a: + * + * mytag_front_ring_t front_ring; + * + * SHARED_RING_INIT(MY_RING, (mytag_sring_t *)shared_page) + * FRONT_RING_INIT(MY_RING, &front_ring, (mytag_sring_t *)shared_page) + * + * Initializing the back follows similarly... + */ + +/* NB: RING SIZING. (a note to ease future debugging...) + * + * Passing size information into the ring macros is made difficult by + * the lack of a reasonable constant declaration in C. To get around this, + * the RING_PARAMS define places the requested size of the ring as the + * static size of the 'size' array in the anonymous RING_PARAMS struct. + * While this struct is never actually instantiated, __SRING_SIZE is + * able to use sizeof() to get at the constant size. + */ + +#define RING_PARAMS(__req_t, __rsp_t, __size) \ +((struct { \ + char size[__size]; \ + __req_t req; \ + __rsp_t rsp; \ + \ +} *) 0) + + +#define DEFINE_RING_TYPES(__name, __params) \ + \ +/* Shared ring entry */ \ +union __name##_sring_entry { \ + typeof ((__params)->req) req; \ + typeof ((__params)->rsp) rsp; \ +} PACKED; \ + \ +/* Shared ring page */ \ +struct __name##_sring { \ + RING_IDX req_prod; \ + RING_IDX rsp_prod; \ + union __name##_sring_entry \ + ring[__SRING_SIZE(__params, sizeof (union __name##_sring_entry))]; \ +} PACKED; \ + \ +/* "Front" end's private variables */ \ +struct __name##_front_ring { \ + RING_IDX req_prod_pvt; \ + RING_IDX rsp_cons; \ + struct __name##_sring *sring; \ +}; \ + \ +/* "Back" end's private variables */ \ +struct __name##_back_ring { \ + RING_IDX rsp_prod_pvt; \ + RING_IDX req_cons; \ + struct __name##_sring *sring; \ +}; \ + \ +/* Syntactic sugar */ \ +typedef struct __name##_sring __name##_sring_t; \ +typedef struct __name##_front_ring __name##_front_ring_t; \ +typedef struct __name##_back_ring __name##_back_ring_t; + +/* + * Macros for manipulating rings. + * + * FRONT_RING_whatever works on the "front end" of a ring: here + * requests are pushed on to the ring and responses taken off it. + * + * BACK_RING_whatever works on the "back end" of a ring: here + * requests are taken off the ring and responses put on. + * + * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL. + * This is OK in 1-for-1 request-response situations where the + * requestor (front end) never has more than SRING_SIZE()-1 + * outstanding requests. + */ + + +/* Initialising empty rings */ +#define SHARED_RING_INIT(_p, _s) do { \ + (_s)->req_prod = 0; \ + (_s)->rsp_prod = 0; \ +} while(0) + +#define FRONT_RING_INIT(_p, _r, _s) do { \ + (_r)->req_prod_pvt = 0; \ + (_r)->rsp_cons = 0; \ + (_r)->sring = (_s); \ +} while (0) + +#define BACK_RING_INIT(_p, _r, _s) do { \ + (_r)->rsp_prod_pvt = 0; \ + (_r)->req_cons = 0; \ + (_r)->sring = (_s); \ +} while (0) + +/* Initialize to existing shared indexes -- for recovery */ +#define FRONT_RING_ATTACH(_p, _r, _s) do { \ + (_r)->sring = (_s); \ + (_r)->req_prod_pvt = (_s)->req_prod; \ + (_r)->rsp_cons = (_s)->rsp_prod; \ +} while (0) + +#define BACK_RING_ATTACH(_p, _r, _s) do { \ + (_r)->sring = (_s); \ + (_r)->rsp_prod_pvt = (_s)->rsp_prod; \ + (_r)->req_cons = (_s)->req_prod; \ +} while (0) + + +/* How to mask off a number for use as an offset into a ring + * N.B. This evalutes its second argument once but its first often */ +#define __SHARED_RING_MASK(_p, _s, _i) \ + ((_i) & (SRING_SIZE((_p), (_s)) - 1)) + +/* How big is this ring? */ +#define RING_SIZE(_p, _r) SRING_SIZE((_p), (_r)->sring) + +/* How many empty slots are on a ring? */ +#define RING_PENDING_REQUESTS(_p, _r) \ + ( ((_r)->req_prod_pvt - (_r)->rsp_cons) ) + +/* Test if there is an empty slot available on the front ring. + * (This is only meaningful from the front. ) + */ +#define RING_FULL(_p, _r) \ + (((_r)->req_prod_pvt - (_r)->rsp_cons) == SRING_SIZE((_p), (_r)->sring)) + +/* Test if there are outstanding messages to be processed on a ring. */ +#define RING_HAS_UNCONSUMED_RESPONSES(_p, _r) \ + ( (_r)->rsp_cons != (_r)->sring->rsp_prod ) + +#define RING_HAS_UNCONSUMED_REQUESTS(_p, _r) \ + ( ((_r)->req_cons != (_r)->sring->req_prod ) && \ + (((_r)->req_cons - (_r)->rsp_prod_pvt) != \ + SRING_SIZE((_p), (_r)->sring)) ) + +/* Test if there are messages waiting to be pushed. */ +#define RING_HAS_UNPUSHED_REQUESTS(_p, _r) \ + ( (_r)->req_prod_pvt != (_r)->sring->req_prod ) + +#define RING_HAS_UNPUSHED_RESPONSES(_p, _r) \ + ( (_r)->rsp_prod_pvt != (_r)->sring->rsp_prod ) + + +/* Copy the private producer pointer into the shared ring so the other end + * can see the updates we've made. */ +#define RING_PUSH_REQUESTS(_p, _r) do { \ + wmb(); \ + (_r)->sring->req_prod = (_r)->req_prod_pvt; \ +} while (0) + +#define RING_PUSH_RESPONSES(_p, _r) do { \ + wmb(); \ + (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ +} while (0) + +/* Direct access to individual ring elements, by index. + */ +#define RING_GET_REQUEST(_p, _r, _idx) \ + (&((_r)->sring->ring[ \ + __SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \ + ].req)) + +#define RING_GET_RESPONSE(_p, _r, _idx) \ + (&((_r)->sring->ring[ \ + __SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \ + ].rsp)) + +/* Loop termination condition: Would the specified index overflow the + * ring? + */ +#define RING_REQUEST_CONS_OVERFLOW(_p, _r, _cons) \ + (((_cons) - (_r)->rsp_prod_pvt) >= SRING_SIZE((_p), (_r)->sring)) + +#endif /* __XEN_PUBLIC_IO_RING_H__ */ -- 2.30.2